package 多线程;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

//使用ReentrantLock比直接使用synchronized更安全，可以替代synchronized进行线程同步。
//
//但是，synchronized可以配合wait和notify实现线程在条件不满足时等待，条件满足时唤醒，用ReentrantLock我们怎么编
//写wait和notify的功能呢？
//
//答案是使用Condition对象来实现wait和notify的功能。
//
//我们仍然以TaskQueue为例，把前面用synchronized实现的功能通过ReentrantLock和Condition来实现：
//
//class TaskQueue {
//    private final Lock lock = new ReentrantLock();
//    private final Condition condition = lock.newCondition();
//    private Queue<String> queue = new LinkedList<>();
//
//    public void addTask(String s) {
//        lock.lock();
//        try {
//            queue.add(s);
//            condition.signalAll();
//        } finally {
//            lock.unlock();
//        }
//    }
//
//    public String getTask() {
//        lock.lock();
//        try {
//            while (queue.isEmpty()) {
//                condition.await();
//            }
//            return queue.remove();
//        } finally {
//            lock.unlock();
//        }
//    }
//}
//可见，使用Condition时，引用的Condition对象必须从Lock实例的newCondition()返回，这样才能获得一个绑定了Lock实例
//的Condition实例。
//
//Condition提供的await()、signal()、signalAll()原理和synchronized锁对象的wait()、notify()、notifyAll()是一致
//的，并且其行为也是一样的：
//
//await()会释放当前锁，进入等待状态；
//
//signal()会唤醒某个等待线程；
//
//signalAll()会唤醒所有等待线程；
//
//唤醒线程从await()返回后需要重新获得锁。
//
//此外，和tryLock()类似，await()可以在等待指定时间后，如果还没有被其他线程通过signal()或signalAll()唤醒，可以自己醒来：
//
//if (condition.await(1, TimeUnit.SECOND)) {
//    // 被其他线程唤醒
//} else {
//    // 指定时间内没有被其他线程唤醒
//}
//可见，使用Condition配合Lock，我们可以实现更灵活的线程同步。

//ReentrantLock() //创建一个 ReentrantLock 的实例

//ReentrantLock(boolean fair) //创建一个具有给定公平策略的 ReentrantLock 
//
//int getHoldCount() //查询当前线程保持此锁的次数
//protected Thread getOwner() //返回目前拥有此锁的线程，如果此锁不被任何线程拥有，则返回 null 
//protected Collection<Thread> getQueuedThreads() //返回一个collection，它包含可能正等待获取此锁的线程 
//int getQueueLength() //返回正等待获取此锁的线程估计数 
//protected Collection<Thread> getWaitingThreads(Condition condition) //返回一个 collection，它包含可能正在等待与此锁相关给定条件的那些线程 
//int getWaitQueueLength(Condition condition) //返回等待与此锁相关的给定条件的线程估计数
//boolean hasQueuedThread(Thread thread) //查询给定线程是否正在等待获取此锁
//boolean hasQueuedThreads() //查询是否有些线程正在等待获取此锁
//boolean hasWaiters(Condition condition) //查询是否有些线程正在等待与此锁有关的给定条件
//boolean isFair() //如果此锁的公平设置为 true，则返回true 
//boolean isHeldByCurrentThread() //查询当前线程是否保持此锁
//boolean isLocked() //查询此锁是否由任意线程保持
//void lock() //获取锁
//void lockInterruptibly() //如果当前线程未被中断，则获取锁。
//Condition newCondition() //返回用来与此 Lock 实例一起使用的 Condition 实例 
//boolean tryLock() //仅在调用时锁未被另一个线程保持的情况下，才获取该锁
//boolean tryLock(long timeout, TimeUnit unit) //如果锁在给定等待时间内没有被另一个线程保持，且当前线程未被中断，则获取该锁 
//void unlock() //试图释放此锁

import java.util.Collection;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

//1.   创建一个类，名为 MyLock ，扩展 ReentrantLock 类。
//public class MyLock extends ReentrantLock {
/*public class 使用Condition extends ReentrantLock {

	// 2. 实现 getOwnerName() 方法。此方法使用Lock类的保护方法 getOwner()， 返回控制锁的线程（如果存在）的名字。
	public String getOwnerName() {
		if (this.getOwner() == null) {
			return "None";
		}
		return this.getOwner().getName();
	}

	// 3. 实现 getThreads() 方法。此方法使用Lock类的保护方法 getQueuedThreads()，返回在锁里的线程的 queued
	// list。
	public Collection<Thread> getThreads() {
		return this.getQueuedThreads();
	}

	// 4. 创建一个类，名为 Task，实现 Runnable 接口.
	public class Task implements Runnable {

		// 5. 声明一个私有 Lock 属性，名为 lock。
		private Lock lock;

		// 6. 实现类的构造函数，初始化它的属性值。
		public Task(Lock lock) {
			this.lock = lock;
		}

		// 7. 实现 run() 方法。创建迭代5次的for循环。
		@Override
		public void run() {
			for (int i = 0; i < 5; i++) {

				// 8. 使用lock()方法获取锁，并打印一条信息。
				lock.lock();
				System.out.printf("%s: Get the Lock.\n", Thread.currentThread().getName());

				// 9. 让线程休眠 500 毫秒。使用 unlock() 释放锁并打印一条信息。
				try {
					TimeUnit.MILLISECONDS.sleep(500);
					System.out.printf("%s: Free the Lock.\n", Thread.currentThread().getName());
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					lock.unlock();
				}
			}
		}
	}

	// 10. 创建例子的主类通过创建一个类，名为 Main 并添加 main()方法。
	public static void main(String[] args) throws Exception {

		// 11. 创建 MyLock 对象，名为 lock。
		// MyLock lock = new MyLock();
		使用Condition lock = new 使用Condition();

		// 12. 创建有5个Thread对象的 array。
		Thread threads[] = new Thread[5];

		// 13. 创建并开始5个线程来执行5个Task对象。
		for (int i = 0; i < 5; i++) {
			Task task = lock.new Task(lock);
			threads[i] = new Thread(task);
			threads[i].start();
		}

		// 14. 创建迭代15次的for循环。
		for (int i = 0; i < 15; i++) {

			// 15. 把锁的拥有者的名字写入操控台。
			System.out.printf("Main: Logging the Lock\n");
			System.out.printf("************************\n");
			System.out.printf("Lock: Owner : %s\n", lock.getOwnerName());

			// 16. 显示锁queued的线程的号码和名字。
			System.out.printf("Lock: Queued Threads: %s\n", lock.hasQueuedThreads()); // 译者注：加上 System
			if (lock.hasQueuedThreads()) {
				System.out.printf("Lock: Queue Length: %d\n", lock.getQueueLength());
				System.out.printf("Lock: Queued Threads: ");
				Collection<Thread> lockedThreads = lock.getThreads();
				for (Thread lockedThread : lockedThreads) {
					System.out.printf("%s ", lockedThread.getName());
				}
				System.out.printf("\n");
			}

			// 17. 显示关于Lock对象的公平性和状态的信息。
			System.out.printf("Lock: Fairness: %s\n", lock.isFair());
			System.out.printf("Lock: Locked: %s\n", lock.isLocked());
			System.out.printf("************************\n");

			// 18. 让线程休眠1秒，并合上类的循环。
			TimeUnit.SECONDS.sleep(1);
		}
	}
}*/
//它是如何工作的…
//
//在这个指南里，你实现的MyLock类扩展了ReentrantLock类来返回信息，除此之外获得不到这些信息 ，因为ReentrantLock 类里的数据都是保护类
//型的。 通过MyLock类实现的方法：
//
//getOwnerName()：只有唯一一个线程可以执行被Lock对象保护的临界区。锁存储了正在执行临界区的线程。此线程会被ReentrantLock类的保护方
//               法 getOwner()返回。 此方法使用 getOwner() 方法来返回线程的名字。
//getThreads()： 当线程正在执行临界区时，其他线程尝试进入临界区就会被放到休眠状态一直到他们可以继续执行为止。ReentrantLock类保护方
//               法getQueuedThreads() 返回 正在等待执行临界区的线程list。此方法返回 getQueuedThreads() 方法返回的结果。
//我们还使用了 ReentrantLock 类里实现的其他方法：
//
//hasQueuedThreads():此方法返回 Boolean 值表明是否有线程在等待获取此锁
//getQueueLength(): 此方法返回等待获取此锁的线程数量
//isLocked(): 此方法返回 Boolean 值表明此锁是否为某个线程所拥有
//isFair(): 此方法返回 Boolean 值表明锁的 fair 模式是否被激活
//更多…
//
//ReentrantLock 类还有其他方法也是用来获取Lock对象的信息的：
//
//getHoldCount(): 返回当前线程获取锁的次数
//isHeldByCurrentThread(): 返回 Boolean 值，表明锁是否为当前线程所拥有

//1）Lock的使用
/*public class 使用Condition {
	private Lock lock = new ReentrantLock();

	public static void main(String[] args) {
		final 使用Condition test = new 使用Condition();
		for (int j = 0; j < 4; j++) {
			new Thread() {
				public void run() {
					test.insert(Thread.currentThread());
				}
			}.start();
		}
	}

	public void insert(Thread thread) {
		lock.lock();
		try {
			System.out.println(thread.getName() + "得到了锁");
			for (int i = 0; i < 5; i++) {
				System.out.println("ThreadName=" + Thread.currentThread().getName() + (" " + (i + 1)));
			}
		} catch (Exception e) {
		} finally {
			System.out.println(thread.getName() + "释放了锁");
			lock.unlock();
		}
	}
}*/
//从运行结果可以看出，当一个线程运行完毕后才把锁释放，其他线程才能执行，其他线程的执行顺序是不确定的。


//2）tryLock()的使用方法

/*public class 使用Condition {
    private Lock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        final 使用Condition test = new 使用Condition();

        for (int j = 0; j < 5; j++) {
			new Thread() {
				public void run() {
					test.insert(Thread.currentThread());
				}
			}.start();
			//TimeUnit.SECONDS.sleep(1);
			//Thread.sleep(1);
		}
    }
    public void insert(Thread thread){
        if(lock.tryLock()) {
            try {
                System.out.println(thread.getName()+"得到了锁");
                for (int i = 0; i < 3; i++) {
                    System.out.println("ThreadName=" + Thread.currentThread().getName() + (" " + (i + 1)));
                }
            } catch (Exception e) {
            }finally {
                System.out.println(thread.getName()+"释放了锁");
                lock.unlock();
            }
        } else {
            System.out.println(thread.getName()+"获取锁失败");
        }
    }
}*/


//3）lockInterruptibly()响应中断的使用方法
//注：只中断指定线程，其他线程照常执行。（本例：指定线程为teread1被指定，thread0和thread2不受影响）
/*public class 使用Condition {
    private Lock lock = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException{
    	使用Condition test1 = new 使用Condition();
        MyThread thread0 = new MyThread(test1);
        MyThread thread1 = new MyThread(test1);
        MyThread thread2 = new MyThread(test1);
        thread0.start();
        thread1.start();
        thread2.start();

        //try {
            Thread.sleep(100);
        //} catch (InterruptedException e) {
        //    e.printStackTrace();
        //}
        thread1.interrupt();
    }

    public void insert(Thread thread) throws InterruptedException {
        lock.lockInterruptibly(); //注意，如果需要正确中断等待锁的线程，必须将获取锁放在外面，然后将InterruptedException抛出
        try {
            System.out.println(thread.getName() + "得到了锁");
            long startTime = System.currentTimeMillis();

            for (int i=0;i<100000000 ;i++ ) {
                if (System.currentTimeMillis() - startTime >= Integer.MAX_VALUE)
                    break;
                //插入数据
            }
        } finally {
            System.out.println(Thread.currentThread().getName() + "执行finally");
            lock.unlock();
            System.out.println(thread.getName() + "释放了锁");
        }
    }

    static class MyThread extends Thread {
        private 使用Condition test;

        public MyThread(使用Condition test) {
            this.test = test;
        }

        @Override
        public void run() {
            try {
                test.insert(Thread.currentThread());
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName() + "被中断");
            }
        }
    }
}*/
//执行结果：
//Thread-0得到了锁
//Thread-1被中断
//Thread-0执行finally
//Thread-0释放了锁
//Thread-2得到了锁
//Thread-2执行finally
//Thread-2释放了锁

//Condition接口使用
//接口的主要实现方法：
//
//1.void await() //造成当前线程在接到信号或被中断之前一直处于等待状态。 
//2.boolean await(long time, TimeUnit unit) //造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。 
//3.long awaitNanos(long nanosTimeout) //造成当前线程在接到信号、被中断或到达指定等待时间之前一直处于等待状态。 
//4.void awaitUninterruptibly() //造成当前线程在接到信号之前一直处于等待状态。 
//5.boolean awaitUntil(Date deadline) //造成当前线程在接到信号、被中断或到达指定最后期限之前一直处于等待状态。 
//6.void signal() //唤醒一个等待线程。 
//7.void signalAll() //唤醒所有等待线程。

//1）Condition实现等待/通知机制
/*public class 使用Condition {

    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        ThreadA a = new ThreadA(service);
        a.start();
        Thread.sleep(3000);
        service.signal_1();
    }
    
    static public class MyService {
        private Lock lock = new ReentrantLock();
        public Condition condition = lock.newCondition();

        public void await_1() {
            lock.lock();
            try {
                System.out.println("await时间为：" + System.currentTimeMillis());
                condition.await();
                System.out.println("这是condition.await()方法之后的语句，condition.signal()方法之后我才被执行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        public void signal_1() {
            lock.lock();
            try {
                System.out.println("signal时间为" + System.currentTimeMillis());
                condition.signal();
                Thread.sleep(3000);
                System.out.println("这是condition.signal()方法之后的语句");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

    static public class ThreadA extends Thread {
        private MyService service;

        public ThreadA(MyService service) {
            this.service = service;
        }

        @Override
        public void run() {
            service.await_1();
        }
    }

}*/

//在使用wait/notify实现等待通知机制的时候我们知道必须执行完notify()方法所在的synchronized代码块后才释放锁。在这里也差不
//多，必须执行完signal所在的try语句块之后才释放锁，condition.await()后的语句才能被执行。
//
//2）多个Condition实例实现等待/通知机制

/*class MyserviceMoreCondition {

    private Lock lock = new ReentrantLock();

    private Condition conditionA = lock.newCondition();
    private Condition conditionB = lock.newCondition();

    public void awaitA() {
        lock.lock();
        try {
            System.out.println("begin awaitA时间为" + System.currentTimeMillis()+ " ThreadName=" + Thread.currentThread().getName());
            conditionA.await();
            System.out.println("end awaitA时间为" + System.currentTimeMillis()+ " ThreadName=" + Thread.currentThread().getName());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void awaitB() {
        lock.lock();
        try {
            System.out.println("begin awaitB时间为" + System.currentTimeMillis()+ " ThreadName=" + Thread.currentThread().getName());
            conditionB.await();
            System.out.println("end awaitB时间为" + System.currentTimeMillis()+ " ThreadName=" + Thread.currentThread().getName());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signalAll_A() {
        lock.lock();
        try {
            System.out.println("signalAll_A时间为" + System.currentTimeMillis()+ " ThreadName=" + Thread.currentThread().getName());
            conditionA.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signalAll_B() {
        lock.lock();
        try {
            System.out.println("signalAll_B时间为" + System.currentTimeMillis()+ " ThreadName=" + Thread.currentThread().getName());
            conditionB.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}
//public class UseMoreConditionWaitNotify {
public class 使用Condition {
    public static void main(String[] args) throws InterruptedException {

        MyserviceMoreCondition service = new MyserviceMoreCondition();

        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();

        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();

        Thread.sleep(3000);
        service.signalAll_A();
        service.signalAll_B();

    }

    static public class ThreadA extends Thread {
        private MyserviceMoreCondition service;
        public ThreadA(MyserviceMoreCondition service) {
            this.service = service;
        }

        @Override
        public void run() {
            service.awaitA();
        }
    }

    static public class ThreadB extends Thread {

        private MyserviceMoreCondition service;

        public ThreadB(MyserviceMoreCondition service) {
            this.service = service;
        }

        @Override
        public void run() {
            service.awaitB();
        }
    }
}
*/

//3）Condition实现顺序执行
//public class ConditionSeqExec {
/*public class 使用Condition {

    volatile private static int nextPrintWho = 1;

    // 默认情况下ReentranLock类使用的是非公平锁
    final private static ReentrantLock lock = new ReentrantLock();

    final private static Condition conditionA = lock.newCondition();
    final private static Condition conditionB = lock.newCondition();
    final private static Condition conditionC = lock.newCondition();

    public static void main(String[] args) {

        Thread threadA = new Thread() {
            public void run() {
                lock.lock();
                try {
                    while (nextPrintWho != 1) {
                        conditionA.await();
                    }

                    for (int i = 0; i < 3; i++) {
                        System.out.println("ThreadA" + (i + 1));
                    }

                    nextPrintWho = 2;
                    //通知conditionB实例的线程运行
                    conditionB.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };

        Thread threadB = new Thread() {
            public void run() {
                lock.lock();
                try {
                    while (nextPrintWho != 2) {
                        conditionB.await();
                    }

                    for (int i = 0; i < 3; i++) {
                        System.out.println("ThreadB" + (i + 1));
                    }

                    nextPrintWho = 3;
                    //通知conditionB实例的线程运行
                    conditionC.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };

        Thread threadC = new Thread() {
            public void run() {
                lock.lock();
                try {
                    while (nextPrintWho != 3) {
                        conditionC.await();
                    }

                    for (int i = 0; i < 3; i++) {
                        System.out.println("ThreadC" + (i + 1));
                    }

                    nextPrintWho = 1;
                    //通知conditionB实例的线程运行
                    conditionA.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        };

        Thread[] array1 = new Thread[5];
        Thread[] array2 = new Thread[5];
        Thread[] array3 = new Thread[5];

        for (int i = 0; i < 5; i++) {
            array1[i] = new Thread(threadA);
            array2[i] = new Thread(threadB);
            array3[i] = new Thread(threadC);

            array1[i].start();
            array2[i].start();
            array3[i].start();
        }
    }

}*/
//在一个线程运行完之后通过condition.signal()/condition.signalAll()方法通知下一个特定的运行运行，就这样循环往复即可。

//ReadWriteLock接口简介
//public interface ReadWriteLock {
//    /**
//     * Returns the lock used for reading.
//     *
//     * @return the lock used for reading
//     */
//    Lock readLock();
//
//    /**
//     * Returns the lock used for writing.
//     *
//     * @return the lock used for writing
//     */
//    Lock writeLock();
//}
//从源码中可知，ReadWriteLock里面只定义了两个方法：一个用来获取读锁，一个用来获取写锁。也就是说将文件的读写操作分开，分成2个锁来分配给线程，
//从而使得多个线程可以同时进行读操作，ReentrantReadWriteLock实现了ReadWriteLock接口。